/*
 * Copyright 2007 Sam Hough
 * 
 * This file is part of GWTS.
 *
 * GWTS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * GWTS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GWTS.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.redspr.gwts;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gargoylesoftware.htmlunit.AlertHandler;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.ThreadManager;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomComment;
import com.gargoylesoftware.htmlunit.html.DomNode;
import com.gargoylesoftware.htmlunit.html.DomText;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlBody;
import com.gargoylesoftware.htmlunit.html.HtmlButton;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlInlineFrame;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlScript;

public class Tryst {
    private static final Map<Class, AbstractHandler> l = new IdentityHashMap();

    Map<Object, DomNode> list = new HashMap<Object, DomNode>();

    List<RequestListener> listeners = new ArrayList();
    static {
        l.put(HtmlElement.class, new HtmlElementHandler());
        l.put(DomText.class, new DomTextHandler());
        l.put(HtmlAnchor.class, new HtmlAnchorHandler());
        l.put(HtmlBody.class, new HtmlBodyHandler());
        l.put(HtmlButton.class, new HtmlButtonHandler());
        l.put(HtmlInlineFrame.class, new HtmlInlineFrameHandler());
        l.put(HtmlScript.class, new HtmlScriptHandler());
        l.put(HtmlPage.class, new HtmlPageHandler());
        l.put(DomComment.class, new DomCommentHandler());
        l.put(HtmlCheckBoxInput.class, new HtmlCheckBoxInputHandler());
    }

    void fix(DomNode node, HttpServletResponse out) throws IOException {
        getHandlerFor(node).handle(this, node, out);
    }

    static AbstractHandler getHandlerFor(final Object c0) {
        Class c = c0.getClass();
        while (c != Object.class) {
            AbstractHandler x = l.get(c);
            if (x != null)
                return x;
            c = c.getSuperclass();
        }
        throw new RuntimeException("Could not find handler for " + c0);
    }

    // TODO 00 this is rubbish
    private String alert;

    private HtmlPage p;

    private WebClient wc = new WebClient(BrowserVersion.FIREFOX_2);

    Tryst(String url) throws Exception { // XXX
        wc.setAlertHandler(new AlertHandler() {
            public void handleAlert(Page arg0, String arg1) {
                alert = arg1;
            }
        });

        wc.setAjaxController(new NicelyResynchronizingAjaxController());

        p = (HtmlPage) wc.getPage(new URL(url));
    }

    void addRequestListener(RequestListener rl) {
        listeners.add(rl);
    }

    void click(HttpServletRequest req, HttpServletResponse res)
            throws IOException {

        if (alert == null) {

            for (String n : (Set<String>) req.getParameterMap().keySet()) {
                if (n.startsWith("click_")) { // XXX magic
                    String name = n.substring(6);
                    DomNode ah = list.get(name);
                    if (ah != null) {
                        for (RequestListener rl : listeners) {
                            rl.update(req, res);
                        }
                        getHandlerFor(ah).click(this, ah);
                    }
                }
            }
        } else {
            alert = null;
        }

        if (alert == null) {

            ThreadManager tm = p.getEnclosingWindow().getThreadManager();

            while (tm.activeCount() > 0) {
                System.out.println("WAit for " + tm.activeCount());
                try {
                    Thread.sleep(1000);
                } catch (Exception ex) {
                }

            }
            list.clear();
            listeners.clear();
            fix(p, res);
        } else {
            PrintWriter out = res.getWriter();
            out.print("<html><body><form><button>" + alert
                    + "</button></form></body></html>");
        }
    }

    int k;

    String getId(DomNode n) {
        String id = "x" + k++;
        list.put(id, n);
        return id;
    }
}
